package com.loe.ktui

import android.content.Context
import android.content.res.TypedArray
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.res.getBooleanOrThrow
import androidx.core.content.res.getDimensionOrThrow
import androidx.recyclerview.widget.*
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.BaseViewHolder
import com.loe.ktui.custom.KtRefreshLayout
import com.loe.ktui.util.*

open class UiList<BEAN>(id: String? = null) : UiView(id)
{
    companion object
    {
        const val TYPE_LIST = "list"
        const val TYPE_GRID = "grid"
        const val TYPE_FALL = "fall"
    }

    var type: String = TYPE_LIST
    var orientation: Int = VERTICAL
    var spanCount: Int = 2
    var reverse = false

    var itemAnimator: RecyclerView.ItemAnimator? = DefaultItemAnimator()

    var itemUI: UiFrameLayout? = null
    fun itemUI(block: UiFrameLayout.() -> Unit)
    {
        itemUI = UiFrameLayout()
        itemUI?.block()
    }

    var itemConvert: (KtFrameLayout.(adapter: BaseQuickAdapter<BEAN, *>, i: Int, bean: BEAN) -> Unit)? = null
    fun itemConvert(itemConvert: KtFrameLayout.(adapter: BaseQuickAdapter<BEAN, *>, i: Int, bean: BEAN) -> Unit)
    {
        this.itemConvert = itemConvert
    }

    var onLoadData: (KtListView<BEAN>.(isRefresh: Boolean) -> Unit)? = null
    fun onLoadData(onLoadData: KtListView<BEAN>.(isRefresh: Boolean) -> Unit)
    {
        this.onLoadData = onLoadData
    }

    var headerUI: UiView? = null
    var footerUI: UiView? = null
    var emptyUI: Any? = ""

    var listSpace: Any? = null
    var listPadding: Any? = null
    var listPaddingH: Any? = null
    var listPaddingV: Any? = null
    var listPaddingLeft: Any? = null
    var listPaddingTop: Any? = null
    var listPaddingRight: Any? = null
    var listPaddingBottom: Any? = null

    var isRefresh: Boolean? = null
    var isLoadMore: Boolean? = null
    var isScroll: Boolean? = null
    var scrollbars: Int? = null

    var scrollBarSize: Any? = null
    var overScrollMode: Int? = null
    var refreshColor: Int? = null
    var onListScroll: (KtListView<BEAN>.(position: Int, top: Int) -> Unit)? = null
    fun onListScroll(onListScroll: KtListView<BEAN>.(position: Int, top: Int) -> Unit)
    {
        this.onListScroll = onListScroll
    }

    var datas: List<BEAN>? = null

    override fun onCreateView(onCreateView: View.() -> Unit)
    {
        this.onCreateView = {
            if (isRefresh == true)
            {
                val c = (this as SwipeRefreshLayout).childCount
                if (c > 0) this.getChildAt(1).onCreateView()
            } else
            {
                this.onCreateView()
            }
        }
    }

    open fun initUI(context: Context, view: KtListView<BEAN>)
    {
        super.initUI(context, view)

        isAlphaClick?.let { view.isAlphaClick = it }

        view.layoutManager = when (type)
        {
            "grid" ->
            {
                GridLayoutManager(context, spanCount, orientation, reverse)
            }
            "fall" ->
            {
                StaggeredGridLayoutManager(spanCount, orientation)
            }
            else ->
            {
                spanCount = 1
                LinearLayoutManager(context, orientation, reverse)
            }
        }

        view.uiAdapter = object : BaseQuickAdapter<BEAN, BaseViewHolder>(if (orientation == RecyclerView.VERTICAL) R.layout.kt_item_ui_v else R.layout.kt_item_ui_h, ArrayList<BEAN>())
        {
            override fun convert(holder: BaseViewHolder, bean: BEAN)
            {
                val vg = holder.itemView as KtFrameLayout
                if (itemUI != null && vg.childCount == 0)
                {
                    itemUI?.initUI(context, vg)
                }
                view.itemConvert?.invoke(vg, view.uiAdapter!!, holder.layoutPosition, bean)
            }
        }
        view.adapter = view.uiAdapter

        view.uiAdapter?.setHeaderFooterEmpty(true, true)
        view.uiAdapter?.setLoadMoreView(KtLoadMoreView())

        view.itemAnimator = itemAnimator

        itemConvert?.let { view.itemConvert = itemConvert }

        onLoadData?.let { on -> view.setOnLoadData { view.on(it) } }

        headerUI?.let {
            view.headerView = it.createView(context)
            view.uiAdapter?.addHeaderView(view.headerView)
        }

        footerUI?.let {
            view.footerView = it.createView(context)
            view.uiAdapter?.addFooterView(view.footerView)
        }

        emptyUI?.let {
            view.emptyView = if (it is UiView)
                it.createView(context)
            else
                    RecyclerView.inflate(context, R.layout.kt_list_empty, null)
        }

        if (view.decoration != null) view.removeItemDecoration(view.decoration!!)
        val space = listSpace.dist
        val startSize = if (view.headerView == null) 0 else 1
        var ps: Array<Int>
        if (listPadding != null)
        {
            val p = listPadding.dist
            ps = arrayOf(p, p, p, p)
        } else
        {
            ps = arrayOf(0, 0, 0, 0)
            if (listPaddingH != null)
            {
                val pH = listPaddingH.dist
                ps[0] = pH
                ps[2] = pH
            }
            if (listPaddingV != null)
            {
                val pV = listPaddingV.dist
                ps[1] = pV
                ps[3] = pV
            }
            if (ps[0] == 0) ps[0] = listPaddingLeft.dist
            if (ps[1] == 0) ps[1] = listPaddingTop.dist
            if (ps[2] == 0) ps[2] = listPaddingRight.dist
            if (ps[3] == 0) ps[3] = listPaddingBottom.dist
        }
        view.decoration = if (spanCount == 1)
        {
            if (orientation == HORIZONTAL)
            {
                KtHorizontalDecoration(ps[0], ps[1], ps[2], ps[3], space, startSize)
            } else
            {
                KtVerticalDecoration(ps[0], ps[1], ps[2], ps[3], space, startSize)
            }
        } else
        {
            KtGridDecoration(ps[0], ps[1], ps[2], ps[3], spanCount, space, startSize)
        }
        view.addItemDecoration(view.decoration!!)

        isRefresh?.let {
            view.isEnableRefresh = it
            if (!it)
            {
                view.refreshLayout?.setOnClickListener(null)
                view.refreshLayout = null
            }
        }

        isLoadMore?.let {
            view.isEnableLoadMore = it
            view.uiAdapter?.setEnableLoadMore(it)
            if (it)
            {
                // 加载更多监听
                view.uiAdapter?.setOnLoadMoreListener({
                    view.refreshLayout?.isEnabled = false

                    view.postDelayed({
                        view.onLoadData?.invoke(false)
                    }, 400)
                }, view)
            } else
            {
                view.uiAdapter?.setOnLoadMoreListener(null, view)
            }
        }

        isScroll?.let {
            view.isScroll = it
            view.isNestedScrollingEnabled = it
            if (it)
            {
                view.overScrollMode = View.OVER_SCROLL_ALWAYS
            } else
            {
                view.overScrollMode = View.OVER_SCROLL_NEVER
            }
        }

        maxWidth?.let { view.maxWidth = it.dist }
        maxHeight?.let { view.maxHeight = it.dist }

        scrollBarSize?.let { view.scrollBarSize = it.dist }
        overScrollMode?.let { view.overScrollMode = it }

        refreshColor?.let {
            view.refreshColor = it
            view.refreshLayout?.setColorSchemeColors(it)
        }

        onListScroll?.let { on -> view.onListScroll = { position, top -> view.on(position, top) } }

        datas?.let { view.uiAdapter?.setNewData(it.toMutableList()) }
    }

    /** 创建view */
    override fun createView(context: Context, parent: ViewGroup?): View
    {
        val view = when(scrollbars)
        {
            VERTICAL -> LayoutInflater.from(context).inflate(R.layout.kt_recyclerview_vertical, null) as KtListView<BEAN>
            HORIZONTAL -> LayoutInflater.from(context).inflate(R.layout.kt_recyclerview_horizontal, null) as KtListView<BEAN>
            else -> KtListView<BEAN>(context)
        }
        initUI(context, view)

        return if (isRefresh == true)
        {
            // 塞入refresh
            view.refreshLayout = SwipeRefreshLayout(context)
            view.refreshLayout?.isEnabled = true
            val listParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
            view.refreshLayout?.addView(view, listParams)
            addToParent(parent, view.refreshLayout!!)
            view.refreshLayout!!
        } else
        {
            addToParent(parent, view)
            if(parent is KtRefreshLayout)
            {
                parent.adapter = view.uiAdapter
            }
            view
        }
    }

    fun createListView(context: Context, parent: ViewGroup? = null): KtListView<BEAN> = createView(context, parent) as KtListView<BEAN>
}

fun <BEAN> Any.ui_List(id: String? = null, block: (UiList<BEAN>.() -> Unit)? = null): UiList<BEAN>
{
    val ui = UiList<BEAN>(id)
    block?.let { ui.it() }
    if (this is UiGroup) addChild(ui)
    return ui
}

open class KtListView<BEAN> : RecyclerView
{
    fun initUI(id: String? = null, block: (UiList<BEAN>.() -> Unit)? = null)
    {
        val ui = UiList<BEAN>(id)
        block?.let { ui.it() }
        ui.initUI(context, this)
    }

    constructor(context: Context) : super(context, null , androidx.recyclerview.R.attr.recyclerViewStyle)
    {
        initXML(null)
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
    {
        initXML(attrs)
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    {
        initXML(attrs)
    }

    private fun initXML(attrs: AttributeSet? = null)
    {
    }

    /******************************************** 原生 ******************************************/

    internal var isScroll = true

    var headerView: View? = null
        internal set

    var footerView: View? = null
        internal set

    var emptyView: View? = null
        set(value)
        {
            field = value
            uiAdapter?.emptyView = value
        }

    var decoration: ItemDecoration? = null

    internal var itemConvert: (KtFrameLayout.(adapter: BaseQuickAdapter<BEAN, *>, i: Int, data: BEAN) -> Unit)? = null

    /** 设置自定义Item处理 */
    fun setItemConvert(itemConvert: (KtFrameLayout.(adapter: BaseQuickAdapter<BEAN, *>, i: Int, data: BEAN) -> Unit)?)
    {
        this.itemConvert = itemConvert
    }

    fun setData(list: List<BEAN>)
    {
        if(list is ArrayList)
        {
            uiAdapter?.setNewData(list)
        }else
        {
            uiAdapter?.setNewData(ArrayList(list))
        }
    }

    var isAlphaClick = false
        set(value)
        {
            field = value
            isClickable = value
        }

    override fun dispatchSetPressed(pressed: Boolean)
    {
        if (isAlphaClick) alpha = if (pressed || !isEnabled) 0.75f else 1f
        super.dispatchSetPressed(pressed)
    }

    override fun setEnabled(enabled: Boolean)
    {
        if (isAlphaClick) alpha = if (enabled) 1f else 0.75f
        super.setEnabled(enabled)
    }

    fun setDefaultEmptyView()
    {
        emptyView = inflate(context, R.layout.kt_list_empty, null)
    }

    /*****************************************   滚动   ****************************************/

    var onListScroll: ((position: Int, top: Int) -> Unit)? = null

    override fun onScrolled(dx: Int, dy: Int)
    {
        if (onListScroll != null)
        {
            val topView = getChildAt(0)
            val position = (topView.layoutParams as LayoutParams).viewAdapterPosition
            val top = topView.top
            onListScroll!!(position, top)
        }
    }

    /***************************************** 加载刷新 ****************************************/

    internal var refreshColor: Int? = null

    /** 刷新View */
    var refreshLayout: SwipeRefreshLayout? = null
        set(value)
        {
            if (isEnableRefresh)
            {
                field = value
                value?.isEnabled = true
                if (refreshColor != null)
                {
                    value?.setColorSchemeColors(refreshColor!!)
                } else
                {
                    value?.setColorSchemeColors(KtColor.main)
                }
                // 刷新监听
                value?.setOnRefreshListener()
                {
                    if (isEnableLoadMore) uiAdapter?.setEnableLoadMore(false)

                    postDelayed({
                        page == 1
                        onLoadData?.invoke(true)
                    }, 400)
                }
            } else
            {
                field = null
            }
        }

    fun refresh()
    {
        refreshLayout?.measure(0, 0)
        refreshLayout?.isRefreshing = true
    }

    fun refreshAuto()
    {
        if (uiAdapter?.data?.isEmpty() == true)
        {
            refresh()
        }
    }

    fun setRefreshing(refreshing: Boolean)
    {
        refreshLayout?.isRefreshing = refreshing
    }

    var size: Int = 10

    internal var isEnableLoadMore = false

    internal var isEnableRefresh = false

    var uiAdapter: BaseQuickAdapter<BEAN, *>? = null

    var page = 1
        private set

    /** 加载监听 */
    internal var onLoadData: ((isRefresh: Boolean) -> Unit)? = null

    /** 设置加载监听 */
    fun setOnLoadData(onLoadData: (isRefresh: Boolean) -> Unit)
    {
        this.onLoadData = onLoadData
    }

    fun loadData(isRefresh: Boolean = true)
    {
        if (isRefresh) page = 1
        onLoadData?.invoke(isRefresh)
    }

    /**
     * 加载完成调用
     */
    fun loadOk(aList: List<BEAN>, isRefresh: Boolean)
    {
        if (isEnableLoadMore)
        {
            refreshLayout?.isRefreshing = false
            if (isRefresh)
            {
                uiAdapter?.data?.clear()
            }
            uiAdapter?.addData(aList)
            if (isRefresh)
            {
                refreshLayout?.isRefreshing = false
                uiAdapter?.setEnableLoadMore(true)
            } else
            {
                uiAdapter?.loadMoreComplete()
                refreshLayout?.isEnabled = true
            }
            if (aList.isEmpty() || aList.size < size)
            {
                uiAdapter?.loadMoreEnd(false)
            }
            page++
        } else
        {
            refreshLayout?.isRefreshing = false
            uiAdapter?.data?.clear()
            uiAdapter?.addData(aList)
        }
    }

    /**
     * 加载失败调用
     */
    fun loadError(isRefresh: Boolean)
    {
        if (isEnableLoadMore)
        {
            if (isRefresh)
            {
                refreshLayout?.isRefreshing = false
            } else
            {
                uiAdapter?.loadMoreFail()
                refreshLayout?.isEnabled = true
            }
        } else
        {
            refreshLayout?.isRefreshing = false
        }
    }

    operator fun get(i: Int): BEAN = uiAdapter?.getItem(i)!!

    operator fun set(i: Int, data: BEAN) = uiAdapter?.setData(i, data!!)

    internal var maxHeight = 0
    internal var maxWidth = 0

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int)
    {
        if (!isScroll)
        {
            // ListView适应ScrollView的效果
            val heightSpec = MeasureSpec.makeMeasureSpec(Int.MAX_VALUE shr 2, MeasureSpec.AT_MOST)
            super.onMeasure(widthMeasureSpec, heightSpec)
        } else
        {
            var widthSpec = widthMeasureSpec
            var heightSpec = heightMeasureSpec
            if (maxHeight > 0)
            {
                heightSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST)
            }
            if (maxWidth > 0)
            {
                widthSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST)
            }

            super.onMeasure(widthSpec, heightSpec)
        }
    }

    fun remove(i: Int) = uiAdapter?.remove(i)
    fun add(bean: BEAN) = uiAdapter?.addData(bean)
    fun add(i: Int, bean: BEAN) = uiAdapter?.addData(i, bean)
    fun notifyDataSetChanged() = uiAdapter?.notifyDataSetChanged()
    fun notifyItemChanged(i: Int) = uiAdapter?.notifyItemChanged(i)
    val itemCount get() = uiAdapter?.itemCount
    val data: MutableList<BEAN>? get() = uiAdapter?.data
}

/** XML使用的列表 */
open class KtRecyclerView : RecyclerView
{
    constructor(context: Context) : super(context)
    {
        initXML()
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
    {
        initXML(context.obtainStyledAttributes(attrs, R.styleable.KtRecyclerView))
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    {
        initXML(context.obtainStyledAttributes(attrs, R.styleable.KtRecyclerView, defStyleAttr, 0))
    }

    private fun initXML(typedArray: TypedArray? = null)
    {
        typedArray?.let()
        {
            if (it.hasValue(R.styleable.KtRecyclerView_kt_corner))
            {
                val corner = it.getDimensionOrThrow(R.styleable.KtRecyclerView_kt_corner).toInt()
                val cornerDirect = KtDirects[it.getInt(R.styleable.KtRecyclerView_kt_cornerDirect, 4)]

                outlineProvider = KtCornerProvider(corner, cornerDirect, this)
            }
            if (it.hasValue(R.styleable.KtRecyclerView_kt_isAlphaClick))
            {
                isAlphaClick = it.getBooleanOrThrow(R.styleable.KtRecyclerView_kt_isAlphaClick)
            }

            if (it.hasValue(R.styleable.KtRecyclerView_kt_maxWidth))
            {
                maxWidth = it.getDimensionOrThrow(R.styleable.KtRecyclerView_kt_maxWidth).toInt()
            }
            if (it.hasValue(R.styleable.KtRecyclerView_kt_maxHeight))
            {
                maxHeight = it.getDimensionOrThrow(R.styleable.KtRecyclerView_kt_maxHeight).toInt()
            }

            val type = it.getInt(R.styleable.KtRecyclerView_kt_list_type, 0)
            var spanCount = it.getInt(R.styleable.KtRecyclerView_kt_list_spanCount, 2)
            val orientation = it.getInt(R.styleable.KtRecyclerView_kt_list_orientation, VERTICAL)
            val reverse = it.getBoolean(R.styleable.KtRecyclerView_kt_isAlphaClick, false)
            layoutManager = when (type)
            {
                1 ->
                {
                    GridLayoutManager(context, spanCount, orientation, reverse)
                }
                2 ->
                {
                    StaggeredGridLayoutManager(spanCount, orientation)
                }
                else ->
                {
                    spanCount = 1
                    LinearLayoutManager(context, orientation, reverse)
                }
            }
            maxWidth = it.getDimensionPixelOffset(R.styleable.KtRecyclerView_kt_maxWidth, 0)
            maxHeight = it.getDimensionPixelOffset(R.styleable.KtRecyclerView_kt_maxHeight, 0)

            isScroll = it.getBoolean(R.styleable.KtRecyclerView_kt_isScroll, true)

            if(!isScroll) itemAnimator = null

            val startSize = it.getInt(R.styleable.KtRecyclerView_kt_list_startSize, 0)
            val space = it.getDimensionPixelOffset(R.styleable.KtRecyclerView_kt_list_space, 0)
            val padding = it.getDimensionPixelOffset(R.styleable.KtRecyclerView_kt_list_padding, 0)
            val paddingH = it.getDimensionPixelOffset(R.styleable.KtRecyclerView_kt_list_paddingH, 0)
            val paddingV = it.getDimensionPixelOffset(R.styleable.KtRecyclerView_kt_list_paddingV, 0)
            val paddingLeft = it.getDimensionPixelOffset(R.styleable.KtRecyclerView_kt_list_space, 0)
            val paddingTop = it.getDimensionPixelOffset(R.styleable.KtRecyclerView_kt_list_paddingTop, 0)
            val paddingRight = it.getDimensionPixelOffset(R.styleable.KtRecyclerView_kt_list_paddingRight, 0)
            val paddingBottom = it.getDimensionPixelOffset(R.styleable.KtRecyclerView_kt_list_paddingBottom, 0)

            val ps: Array<Int>
            if (padding != 0)
            {
                ps = arrayOf(padding, padding, padding, padding)
            } else
            {
                ps = arrayOf(0, 0, 0, 0)
                if (paddingH != 0)
                {
                    ps[0] = paddingH
                    ps[2] = paddingH
                }
                if (paddingV != 0)
                {
                    ps[1] = paddingV
                    ps[3] = paddingV
                }
                if (ps[0] == 0) ps[0] = paddingLeft
                if (ps[1] == 0) ps[1] = paddingTop
                if (ps[2] == 0) ps[2] = paddingRight
                if (ps[3] == 0) ps[3] = paddingBottom
            }
            decoration = if (spanCount == 1)
            {
                if (orientation == HORIZONTAL)
                {
                    KtHorizontalDecoration(ps[0], ps[1], ps[2], ps[3], space, startSize)
                } else
                {
                    KtVerticalDecoration(ps[0], ps[1], ps[2], ps[3], space, startSize)
                }
            } else
            {
                KtGridDecoration(ps[0], ps[1], ps[2], ps[3], spanCount, space, startSize)
            }
            addItemDecoration(decoration!!)

            it.recycle()
        }
    }

    fun setDefaultEmptyView()
    {
        if(adapter is BaseQuickAdapter<*, *>)
        {
            (adapter as BaseQuickAdapter<*, *>).emptyView = inflate(context, R.layout.kt_list_empty, null)
        }
    }

    /******************************************** 原生 ******************************************/

    var isScroll = true
        set(value)
        {
            field = value
            isNestedScrollingEnabled = value
        }

    internal var decoration: ItemDecoration? = null

    var isAlphaClick = false
        set(value)
        {
            field = value
            isClickable = value
        }

    override fun dispatchSetPressed(pressed: Boolean)
    {
        if (isAlphaClick) alpha = if (pressed || !isEnabled) 0.75f else 1f
        super.dispatchSetPressed(pressed)
    }

    override fun setEnabled(enabled: Boolean)
    {
        if (isAlphaClick) alpha = if (enabled) 1f else 0.75f
        super.setEnabled(enabled)
    }

    /*****************************************   滚动   ****************************************/

    internal var onListScroll: ((position: Int, top: Int) -> Unit)? = null

    fun setOnListScroll(onListScroll: (position: Int, top: Int) -> Unit)
    {
        this.onListScroll = onListScroll
    }

    override fun onScrolled(dx: Int, dy: Int)
    {
        if (onListScroll != null)
        {
            val topView = getChildAt(0)
            val position = (topView.layoutParams as LayoutParams).viewAdapterPosition
            val top = topView.top
            onListScroll!!(position, top)
        }
    }

    internal var maxHeight = 0
    internal var maxWidth = 0

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int)
    {
        if (!isScroll)
        {
            if (maxHeight > 0)
            {
                val heightSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST)
                super.onMeasure(widthMeasureSpec, heightSpec)
            } else
            {
                // ListView适应ScrollView的效果
                val heightSpec = MeasureSpec.makeMeasureSpec(Int.MAX_VALUE shr 2, MeasureSpec.AT_MOST)
                super.onMeasure(widthMeasureSpec, heightSpec)
            }
        } else
        {
            var widthSpec = widthMeasureSpec
            var heightSpec = heightMeasureSpec
            if (maxHeight > 0)
            {
                heightSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST)
            }
            if (maxWidth > 0)
            {
                widthSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST)
            }

            super.onMeasure(widthSpec, heightSpec)
        }
    }

    fun setMaxHeight(maxHeight: Int)
    {
        this.maxHeight = maxHeight
        requestLayout()
    }
}